--versión absoluta con volumen independiente al sistema
require "import"
import "android.os.Handler"
import "android.widget.LinearLayout"
import "android.widget.SeekBar"
import "android.widget.TextView"
import "android.widget.Button"
import "android.widget.ImageView"
import "android.widget.ListView"
import "android.view.View"
import "android.media.MediaPlayer"
import "android.content.DialogInterface"
import "android.view.WindowManager"
import "android.content.Intent"
import "android.provider.Settings"
import "android.content.pm.PackageManager"
import "android.content.Context"
import "android.os.Build"
import "android.os.VibrationEffect"
import "android.os.Vibrator"
import "android.widget.Toast"
import "java.io.File"
import "java.lang.String"
import "java.io.FileReader"
import "java.io.FileWriter"
import "java.util.ArrayList"
import "android.view.KeyEvent"
import "java.io.BufferedWriter"
import "java.io.BufferedReader"
import "android.graphics.Color"
import "android.widget.EditText"
import "android.app.AlertDialog"
import "android.app.ProgressDialog"
import "android.graphics.drawable.ColorDrawable"
import "android.widget.Spinner"
import "android.widget.PageView"
import "android.widget.CardView"
import "android.widget.ArrayAdapter"
import "android.widget.RippleLayout"
import "android.widget.RelativeLayout"
import "android.media.AudioManager"
import "android.provider.MediaStore"
import "java.io.FileOutputStream"
import "java.io.OutputStreamWriter"
import "java.io.InputStreamReader"
import "java.io.FileInputStream"
import "java.text.SimpleDateFormat"
import "java.util.Date"
import "android.content.ContentValues"
import "android.media.MediaMuxer"
import "android.media.MediaFormat"
import "android.content.*"
import "android.net.Uri"
import "android.widget.*"
import "java.lang.reflect.Array"
import "java.lang.System"
import "android.os.Environment"
import "com.androlua.*"
context = activity or service
vibrator = context.getSystemService(Context.VIBRATOR_SERVICE)
if isPlaying then
mediaPlayer.stop()
mediaPlayer.reset()
isPlaying = false
currentSoundFilePath = nil
end
--fin de bibliotecas
currentVolume = 10
-- Variable global para almacenar la posición de la pista actual
currentSoundIndex = 0
folderPath = "/storage/emulated/0/Grabación con Plugin"
folder = File(folderPath)
if not folder.exists() then
success = folder.mkdirs()
if success then
service.asyncSpeak(folderPath)
else
service.asyncSpeak("لا يمكن إنشاء مجلد في, " .. folderPath)
end
end
folderPath = "/storage/emulated/0/Music2"
folder = File(folderPath)
if not folder.exists() then
success = folder.mkdirs()
if success then
service.asyncSpeak(folderPath)
else
service.asyncSpeak("لا يمكن إنشاء مجلد في, " .. folderPath)
end
end
folderPath = "/storage/emulated/0/lectura actual"
folder = File(folderPath)
if not folder.exists() then
success = folder.mkdirs()
if success then
service.asyncSpeak(folderPath)
else
service.asyncSpeak("لا يمكن إنشاء مجلد في, " .. folderPath)
end
end
folderPath = "/storage/emulated/0/المفضلة"
folder = File(folderPath)
if not folder.exists() then
success = folder.mkdirs()
if success then
service.asyncSpeak(folderPath)
else
service.asyncSpeak("لا يمكن إنشاء مجلد في, " .. folderPath)
end
end
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_ADDED }
-- Crear una selección para obtener todos los archivos de audio
selection = MediaStore.Audio.Media.IS_MUSIC .. " != 0"
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, nil, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateAdded = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_ADDED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
creationTime = cursor.getLong(columnIndexDateAdded) * 1000
-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, creationTime = creationTime})end
cursor.close()
-- Ordenar la tabla según la fecha de creación, de más nuevo a más viejo
table.sort(soundFilePaths, function(a, b)
return a.creationTime > b.creationTime
end)
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")
return false
end
-- Verificar si se encontraron archivos de música
if #soundFilePaths > 0 then
-- Continuar con el procesamiento de los archivos de música
else
service.asyncSpeak("لم يتم العثور على ملفات موسيقى على الجهاز.")
return false
end
-- Inicializar los resultados de búsqueda
currentMatchIndex = 1
matches = {}
--marcador funciones
function buscar(query)
local queryLower = query:lower()
matches = {}-- Limpiar los resultados de la búsqueda anterior
for i, item in ipairs(adapterItems) do
local text = item
if text:lower():find(queryLower) then
table.insert(matches, i)-- Almacenar el índice de las coincidencias
end
end
if #matches > 0 then
service.asyncSpeak("Se encontraron " .. tostring(#matches) .. " coincidencias.")
currentMatchIndex = 1
list.setSelection(matches[currentMatchIndex] - 1)
else
service.asyncSpeak("بدون نتائج")
end
end
function moveToNextMatch()
if #matches > 0 then
currentMatchIndex = currentMatchIndex + 1
if currentMatchIndex > #matches then
currentMatchIndex = 1
-- Envolverse al inicio después de la última coincidencia
end
list.setSelection(matches[currentMatchIndex] - 1)
else
service.asyncSpeak("لا توجد نتائج أخرى.")
end
end
function scrollToMatch(matchIndex)
local y = editTexts[matchIndex].getTop()
scrollView.post(Runnable({run=function()
scrollView.scrollTo(0, y)
end}))
service.asyncSpeak("Desplazándose a la coincidencia " .. tostring(currentMatchIndex) .. " de " .. tostring(#matches))
end
function nextMatch()
if #matches > 0 then
-- Si hay coincidencias
currentMatchIndex = currentMatchIndex % #matches + 1
-- Ir a la siguiente coincidencia, volver a la primera después de la última
scrollToMatch(matches[currentMatchIndex])-- Desplazarse a la coincidencia
else
service.asyncSpeak("بدون نتائج")
end
end
function sendFileToFolder(position)-- Obtener la ruta del archivo seleccionado
selectedSoundFilePath = soundFilePaths[position + 1].filePath
-- Definir la ruta de destino en la carpeta de المفضلة
destinationFolder = "/storage/emulated/0/المفضلة/"-- Obtener el nombre del archivo del path
fileName = selectedSoundFilePath:match("^.+/(.+)$")-- Construir la ruta de destino completa
destinationPath = destinationFolder .. fileName-- Leer el contenido del archivo original
fileContent = io.open(selectedSoundFilePath, "rb"):read("*all")-- Escribir el contenido en el archivo de destino
destinationFile = io.open(destinationPath, "wb")
if destinationFile then
destinationFile:write(fileContent)
destinationFile:close()
service.asyncSpeak("تم نسخ الملف إلى مجلد المفضلة, ")
else
service.asyncSpeak("تعذر نسخ الملف إلى مجلد المفضلة, ")end
require "import"
import "android.content.Context"
import "android.os.Vibrator"
context = activity or service
vibrator = context.getSystemService(Context.VIBRATOR_SERVICE)
if vibrator.hasVibrator() then
vibrator.vibrate(200)
end
return true
end
function closeDialog()
if isPlaying then
mediaPlayer.stop()
mediaPlayer.reset()
isPlaying = false
currentSoundFilePath = nil
end
end
function cargarArchivosUltimosModificados4()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir las carpetas a escanear en el almacenamiento interno
foldersToScan = {
"/storage/emulated/0/lectura actual"
}
-- Crear unalista de carpetas a partir de las rutas
folderList = ArrayList()
for _, folderPath in ipairs(foldersToScan) do
folderList.add(File(folderPath))end
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_MODIFIED }
-- Crear una selección para restringir las carpetas de escaneo
selection = MediaStore.Audio.Media.DATA .. " LIKE ?"
for i = 2, folderList.size() do
selection = selection .. " OR " .. MediaStore.Audio.Media.DATA .. " LIKE ?"end
-- Crear los argumentos para la selección
selectionArgs = {}
for i = 1, folderList.size() do
selectionArgs[i] = folderList.get(i - 1).getAbsolutePath() .. "%"
end
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateModified = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_MODIFIED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
modifiedTime = cursor.getLong(columnIndexDateModified) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, modifiedTime = modifiedTime})end
cursor.close()
-- Ordenar la tabla por nombre de archivo, en orden alfabético
table.sort(soundFilePaths, function(a, b)
return a.displayName < b.displayName
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)-- Desplazarse a la parte superior de lalista
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات صوتية في المُجُلَّدات المحددة.")
end
end
function cargarArchivosUltimosModificados5()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir las carpetas a escanear en el almacenamiento interno
foldersToScan = {
"/storage/emulated/0/المفضلة"
}
-- Crear unalista de carpetas a partir de las rutas
folderList = ArrayList()
for _, folderPath in ipairs(foldersToScan) do
folderList.add(File(folderPath))end
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_MODIFIED }
-- Crear una selección para restringir las carpetas de escaneo
selection = MediaStore.Audio.Media.DATA .. " LIKE ?"
for i = 2, folderList.size() do
selection = selection .. " OR " .. MediaStore.Audio.Media.DATA .. " LIKE ?"end
-- Crear los argumentos para la selección
selectionArgs = {}
for i = 1, folderList.size() do
selectionArgs[i] = folderList.get(i - 1).getAbsolutePath() .. "%"end
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateModified = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_MODIFIED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
modifiedTime = cursor.getLong(columnIndexDateModified) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, modifiedTime = modifiedTime})end
cursor.close()
-- Ordenar la tabla por nombre de archivo, en orden alfabético
table.sort(soundFilePaths, function(a, b)
return a.displayName < b.displayName
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)
-- Desplazarse a la parte superior de lalista
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات صوتية في المُجُلَّدات المحددة.")
end
end
function cargarArchivosMasAntiguos()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_ADDED }
-- Crear una selección para obtener todos los archivos de audio
selection = MediaStore.Audio.Media.IS_MUSIC .. "!= 0"
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, nil, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateAdded = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_ADDED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
creationTime = cursor.getLong(columnIndexDateAdded) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, creationTime = creationTime})end
cursor.close()
-- Ordenar la tabla según la fecha de creación, de más antiguo a más nuevo
table.sort(soundFilePaths, function(a, b)
return a.creationTime < b.creationTime
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)-- Desplazarse a la parte superior de lalista
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات موسيقى على الجهاز.")
end
end
function cargarArchivos()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_ADDED }
-- Crear una selección para obtener todos los archivos de audio
selection = MediaStore.Audio.Media.IS_MUSIC .. " != 0"
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, nil, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateAdded = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_ADDED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
creationTime = cursor.getLong(columnIndexDateAdded) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, creationTime = creationTime})end
cursor.close()
-- Ordenar la tabla según la fecha de creación, de más nuevo a más viejo
table.sort(soundFilePaths, function(a, b)
return a.creationTime > b.creationTime
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات موسيقى على الجهاز.")
end
end
function cargarArchivosUltimosModificados3()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir las carpetas a escanear en el almacenamiento interno
foldersToScan = {
"/storage/emulated/0/Download"
}
-- Crear unalista de carpetas a partir de las rutas
folderList = ArrayList()
for _, folderPath in ipairs(foldersToScan) do
folderList.add(File(folderPath))end
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_MODIFIED }
-- Crear una selección para restringir las carpetas de escaneo
selection = MediaStore.Audio.Media.DATA .. " LIKE ?"
for i = 2, folderList.size() do
selection = selection .. " OR " .. MediaStore.Audio.Media.DATA .. " LIKE ?"end
-- Crear los argumentos para la selección
selectionArgs = {}
for i = 1, folderList.size() do
selectionArgs[i] = folderList.get(i - 1).getAbsolutePath() .. "%"end
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateModified = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_MODIFIED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
modifiedTime = cursor.getLong(columnIndexDateModified) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, modifiedTime = modifiedTime})end
cursor.close()
-- Ordenar la tabla según la fecha de última modificación, de más reciente a más antiguo
table.sort(soundFilePaths, function(a, b)
return a.modifiedTime > b.modifiedTime
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)-- Desplazarse a la parte superior de lalista
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات صوتية في المُجُلَّدات المحددة.")
end
end
function cargarArchivosUltimosModificados2()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir las carpetas a escanear en el almacenamiento interno
foldersToScan = {
"/storage/emulated/0/Music"
}
-- Crear unalista de carpetas a partir de las rutas
folderList = ArrayList()
for _, folderPath in ipairs(foldersToScan) do
folderList.add(File(folderPath))end
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_MODIFIED }
-- Crear una selección para restringir las carpetas de escaneo
selection = MediaStore.Audio.Media.DATA .. " LIKE ?"
for i = 2, folderList.size() do
selection = selection .. " OR " .. MediaStore.Audio.Media.DATA .. " LIKE ?"end
-- Crear los argumentos para la selección
selectionArgs = {}
for i = 1, folderList.size() do
selectionArgs[i] = folderList.get(i - 1).getAbsolutePath() .. "%"end
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateModified = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_MODIFIED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
modifiedTime = cursor.getLong(columnIndexDateModified) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, modifiedTime = modifiedTime})end
cursor.close()
-- Ordenar la tabla según la fecha de última modificación, de más reciente a más antiguo
table.sort(soundFilePaths, function(a, b)
return a.modifiedTime > b.modifiedTime
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)-- Desplazarse a la parte superior de lalista
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات صوتية في المُجُلَّدات المحددة.")
end
end
function cargarArchivosUltimosModificados()-- Limpiar la tabla existente
soundFilePaths = {}
-- Obtener el contexto de la aplicación de Android
context = service.getContext()
-- Definir las carpetas a escanear en el almacenamiento interno
foldersToScan = {
"/storage/emulated/0/Music2"
}
-- Crear unalista de carpetas a partir de las rutas
folderList = ArrayList()
for _, folderPath in ipairs(foldersToScan) do
folderList.add(File(folderPath))end
-- Definir la proyección para la consulta de MediaStore
projection = { MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.DATE_MODIFIED }
-- Crear una selección para restringir las carpetas de escaneo
selection = MediaStore.Audio.Media.DATA .. " LIKE ?"
for i = 2, folderList.size() do
selection = selection .. " OR " .. MediaStore.Audio.Media.DATA .. " LIKE ?"end
-- Crear los argumentos para la selección
selectionArgs = {}
for i = 1, folderList.size() do
selectionArgs[i] = folderList.get(i - 1).getAbsolutePath() .. "%"end
-- Consultar la base de datos de MediaStore para obtener los archivos de música
cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, null)
if cursor ~= nil then
columnIndexData = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
columnIndexDisplayName = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
columnIndexDateModified = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATE_MODIFIED)
while cursor.moveToNext() do
filePath = cursor.getString(columnIndexData)
displayName = cursor.getString(columnIndexDisplayName)
modifiedTime = cursor.getLong(columnIndexDateModified) * 1000-- Convertir a milisegundos
table.insert(soundFilePaths, { filePath = filePath, displayName = displayName, modifiedTime = modifiedTime})end
cursor.close()
-- Ordenar la tabla según la fecha de última modificación, de más reciente a más antiguo
table.sort(soundFilePaths, function(a, b)
return a.modifiedTime > b.modifiedTime
end)
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)-- Desplazarse a la parte superior de lalista
else
service.asyncSpeak("لا يمكن الوصول إلى مكتبة موسيقى Android.")end
-- Verificar si se encontraron archivos de música
if #soundFilePaths == 0 then
service.asyncSpeak("لم يتم العثور على ملفات صوتية في المُجُلَّدات المحددة.")
end
end
function renameItem(position)
fileData = soundFilePaths[position + 1]
file = File(fileData.filePath)
fileName, fileExtension = string.match(fileData.displayName, "(.-)(%.%w+)$")-- Obtener el nombre y la extensión del archivo
renameDialog = LuaDialog(context)
renameDialog.setTitle("اكتب الاسم")
input = EditText(context)
input.setText(fileName)
-- Utilizar solo el nombre del archivo, sin la extensión
renameDialog.setView(input)
renameDialog.setPositiveButton("موافق", DialogInterface.OnClickListener {
onClick = function(dialog, which)
newFileName = tostring(input.getText())
newFilePath = file.getParent() .. "/" .. newFileName .. fileExtension
-- Agregar la extensión nuevamente al nuevo nombre de archivo
newFile = File(newFilePath)
if file.renameTo(newFile) then
fileData.displayName = newFileName .. fileExtension
-- Actualizar el nombre de archivo en lalista
adapterItems[position + 1] = fileData-- Actualizar el elemento en adapterItems
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
service.asyncSpeak("تمت إعادة تسمية الملف بنجاح.")
cargarArchivos()
-- dlg.dismiss()-- Comentado para mantener la interfaz abierta
else
service.asyncSpeak("حدث خطأ أثناء إعادة تسمية الملف.")end
dialog.dismiss()end
})
renameDialog.setNegativeButton("إلغاء", DialogInterface.OnClickListener {
onClick = function(dialog, which)
dialog.dismiss()end
})
renameDialog.show()end
function shareFile(position)
selectedSoundFilePath = soundFilePaths[position + 1].filePath
-- Llama a la función personalizada service.shareFile para compartir el archivo
service.shareFile(selectedSoundFilePath)
dlg.dismiss()end
function deleteItem(position)
fileData = soundFilePaths[position + 1]
file = File(fileData.filePath)
confirmationDialog = LuaDialog(context)
confirmationDialog.setTitle("هل تريد حذف هذا ملف?")
confirmationDialog.setMessage("¿هل أنت متأكد أنك تريد حذف هذا الملف?")
confirmationDialog.setPositiveButton("موافق", DialogInterface.OnClickListener {
onClick = function(dialog, which)
file.delete()
table.remove(soundFilePaths, position + 1)
service.asyncSpeak("تم حذف الملف بنجاح.")
-- Actualizar la vista de lalista
list.adapter.clear()
for i, fileData in ipairs(soundFilePaths) do
list.adapter.add(fileData.displayName)end
list.adapter.notifyDataSetChanged()
list.smoothScrollToPosition(0)-- Desplazarse a la parte superior de lalista
cargarArchivos()end
})
confirmationDialog.setNegativeButton("إلغاء", DialogInterface.OnClickListener {
onClick = function(dialog, which)
dialog.dismiss()end
})
confirmationDialog.show()end
--marcador función de tiempo para barra de deslizamiento
Runnable = luajava.bindClass("java.lang.Runnable")
DelayedRunnable = Runnable {
run = function()
currentPosition =mediaPlayer.getCurrentPosition()
id_startTime.setText(formatTime(currentPosition))
id_Progress.setProgress(currentPosition)
updateHandler.postDelayed(DelayedRunnable.run, 1000)end
}
currentPosition = 0
totalDuration = 0
updateHandler = Handler()
function formatTime(duration)
minutes = math.floor(duration / 60000)
seconds = math.floor((duration % 60000) / 1000)
return string.format("%02d:%02d", minutes, seconds)end
function stopUpdateHandler()
updateHandler.removeCallbacksAndMessages(nil)end
--marcador funciones de reproducción
function stopPauseButtonClicked()
if isPlaying then
-- Pausar la reproducción
mediaPlayer.pause()
isPlaying = false
else
-- Reanudar la reproducción
mediaPlayer.start()
isPlaying = true
end
end
function playNextTrack()
local nextPosition = currentSoundIndex + 1
if nextPosition <= #soundFilePaths then
local nextSoundFilePath = soundFilePaths[nextPosition].filePath
playSound(nextSoundFilePath)
end
end
function playPreviousTrack()
local previousPosition = currentSoundIndex - 1
if previousPosition >= 1 then
local previousSoundFilePath = soundFilePaths[previousPosition].filePath
playSound(previousSoundFilePath)
end
end
function playSound(soundFilePath)
if currentSoundFilePath == soundFilePath then
-- Detener la reproducción de la pista actual
mediaPlayer.stop()
mediaPlayer.reset()
isPlaying = false
currentSoundFilePath = nil
stopUpdateHandler()
return
end
if isPlaying then
mediaPlayer.stop()
mediaPlayer.reset()
stopUpdateHandler()
end
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC)
mediaPlayer.reset()
mediaPlayer.setDataSource(soundFilePath)
mediaPlayer.prepare()
mediaPlayer.start()
isPlaying = true
currentSoundFilePath = soundFilePath
totalDuration =mediaPlayer.getDuration()
id_endTime.setText(formatTime(totalDuration))
id_Progress.setMax(totalDuration)
currentPosition =mediaPlayer.getCurrentPosition()
id_startTime.setText(formatTime(currentPosition))
id_Progress.setProgress(currentPosition)
id_Progress.setOnSeekBarChangeListener({
onProgressChanged = function(seekBar, progress, fromUser)
-- Verificar si el cambio de progreso proviene del usuario (arrastre) y no de la reproducción automática
if fromUser then
-- Actualizar el progreso de reproducción en el reproductor de medios
mediaPlayer.seekTo(progress)
currentPosition = progress
id_startTime.setText(formatTime(currentPosition))
end
end,
onStartTrackingTouch = function(seekBar)
-- Aquí puedes realizar alguna acción cuando se comienza a arrastrar la barra de progreso, si es necesario
end,
onStopTrackingTouch = function(seekBar)
-- Aquí puedes realizar alguna acción cuando se detiene el arrastre de la barra de progreso, si es necesario
end
})
--marcador función de volumen
mediaPlayer.setVolume(currentVolume / 100, currentVolume / 100)
-- Establece el máximo de la barra de deslizamiento a 100 para facilitar la manipulación
id_Volume.setMax(100)
id_Volume.setProgress(currentVolume)
id_Volume.setOnSeekBarChangeListener({
onProgressChanged = function(seekBar, progress, fromUser)
if fromUser then
-- Actualiza el volumen de reproducción cuando el usuario arrastra la barra de deslizamiento
mediaPlayer.setVolume(progress / 100, progress / 100)
currentVolume = progress
end
end,
onStartTrackingTouch = function(seekBar)
-- Aquí puedes realizar alguna acción cuando se comienza a arrastrar la barra de progreso, si es necesario
end,
onStopTrackingTouch = function(seekBar)
-- Aquí puedes realizar alguna acción cuando se detiene el arrastre de la barra de progreso, si es necesario
end
})
updateHandler.postDelayed(DelayedRunnable, 1000)
run = function()
currentPosition =mediaPlayer.getCurrentPosition()
id_startTime.setText(formatTime(currentPosition))
id_Progress.setProgress(currentPosition)
updateHandler.postDelayed(this, 1000)end
for i, fileData in ipairs(soundFilePaths) do
if fileData.filePath == soundFilePath then
currentSoundIndex = i
break
end
end
mediaPlayer.setOnCompletionListener({
onCompletion = function(mp)
nextPosition = currentSoundIndex + 1
if nextPosition <= #soundFilePaths then
nextSoundFilePath = soundFilePaths[nextPosition].filePath
playSound(nextSoundFilePath)
end
end
})end
--marcador del layout
layout = {
LinearLayout;
layout_width = "fill";
layout_height = "fill";
backgroundColor = "0xFF000000";
orientation = "vertical";
{
TextView;
text = "مُشغِّلُ الصوتيات";
textColor="#ffffff58";
textSize = "20sp";
gravity = "center";
layout_width = "fill";
padding = "16dp";
},
{
TextView;
id = "musicFileCount";
text = "تمَّ العثورُ على " .. #soundFilePaths .. "ملفا صوتيا.";
textSize = "20sp";
gravity = "center";
layout_width = "fill";
padding = "10dp";
},
{
SeekBar;
contentDescription="مستوى الصوت: ",
id = "id_Volume";
layout_width = "fill";
layout_height = "wrap";
},
{
EditText;
id = "searchEditText";
hint = "بحث";
background="#350000ff",
textSize = "20sp";
layout_width = "fill";
layout_height = "wrap";
},
{
Button;
text = "النتيجةُ التالية";
background="#8b0000ff",
textSize = "20sp";
layout_width = "fill";-- Aquí se ha modificado el layout_width a "fill"
onClick = function(view)
moveToNextMatch()
end;
},
{
CardView;
layout_width = "fill";
layout_weight = "1";
backgroundColor = "0xFF202125";
cardElevation = 0;
radius = 0;
{
PageView;
id = "id_page";
layout_width = "fill";
layout_height = "fill";
backgroundColor = "0xFF000000";
padding = "5dp";
pages = {
--marcador páginas
{
ListView;
id = "list";
fastScrollEnabled = false;
layout_width = "fill";
layout_height = "fill";
},
},
},
},
{
CardView;
layout_width = "fill";
layout_margin = "0dp";
backgroundColor = "0xFF202125";
cardElevation = 0;
radius = 0;
id = "t2";
{
LinearLayout;
layout_width = "fill";
orientation = "vertical";
{
LinearLayout;
layout_width = "fill";
layout_margin = "6dp";
{
SeekBar;
id = "id_Progress";
contentDescription="تقديم|ترجيع: ",
layout_width = "fill";
layout_height = "wrap";
},
},
{
TextView;
text = "00:00";
textColor = "0xFFFFFFFF";
id = "id_startTime";
},
{
TextView;
text = "00:00";
textColor = "0xFFFFFFFF";
id = "id_endTime";
},
{
LinearLayout;
layout_width = "fill";
orientation = "horizontal";
{
Button;
id = "id_previousButton";
text = "المَقْطَعُ السابق";
layout_weight = "1";
background="#b600ffff",
onClick = "playPreviousTrack";
},
{
Button;
id = "id_playpauseButton";
text = "تشغيل|إيقاف";
layout_weight = "1";
background="#ff00c500",
onClick = "stopPauseButtonClicked";
},
{
Button;
id = "id_nextButton";
text = "المَقْطَعُ التالي";
layout_weight = "1";
background="#b600ffff",
onClick = "playNextTrack";
},
},
},
},
{
Button;
text = "إغلاق";
background="#ff600000",
layout_width = "fill";
-- Aquí se ha modificado el layout_width a "fill"
onClick = function(view)
dlg.dismiss()end;
},
}
--marcador fin de botones
mediaPlayer = MediaPlayer()
isPlaying = false
currentSoundFilePath = nil
dlg = LuaDialog(service)
dlg.View = loadlayout(layout)
adapterItems = {}
for i, fileData in ipairs(soundFilePaths) do
table.insert(adapterItems, fileData.displayName)end
list.adapter = ArrayAdapter(service, android.R.layout.simple_list_item_1, adapterItems)
dlg.show()
searchEditText.addTextChangedListener({
onTextChanged = function(s, start, before, count)
buscar(s.toString())end
})
list.onItemClick = function(l, v, position, id)
selectedSoundFilePath = soundFilePaths[position + 1].filePath
playSound(selectedSoundFilePath)
end
--marcador inicio de pulsado largo
list.onItemLongClick = function(l, v, position, id)
isLongPress = true
options = {"حذف", "مشاركة", "إعادة تسمية", "الأحدث", "الأقدم", "مجلد الموسيقى 2", "مجلد الموسيقى", "مجلد التنزيلات", "القراءة الحالية", "المفضلة", "اضافة إلى المفضلة"}
dialog = LuaDialog(context)
dialog.setTitle("خيارات الملف")
layout = {
LinearLayout,
orientation = LinearLayout.VERTICAL,
{
Button,
text = options[1],
layout_width = "fill";
onClick = function(view)
deleteItem(position)
dialog.dismiss()
end
},
{
Button,
text = options[2],
layout_width = "fill";
onClick = function(view)
shareFile(position)
dialog.dismiss()
end
},
{
Button,
text = options[3],
layout_width = "fill";
onClick = function(view)
renameItem(position)
dialog.dismiss()
end
},
{
Button,
text = options[4],
layout_width = "fill";
onClick = function(view)
cargarArchivos()
dialog.dismiss()end
},
{
Button,
text = options[5],
layout_width = "fill";
onClick = function(view)
cargarArchivosMasAntiguos()
dialog.dismiss()end
},
{
Button,
text = options[6],
layout_width = "fill";
onClick = function(view)
cargarArchivosUltimosModificados()
dialog.dismiss()end
},
{Button,
text = options[7],
layout_width = "fill";
onClick = function(view)
cargarArchivosUltimosModificados2()
dialog.dismiss()end
},
{
Button,
text = options[8],
layout_width = "fill";
onClick = function(view)
cargarArchivosUltimosModificados3()
dialog.dismiss()end
},
{
Button,
text = options[9],
layout_width = "fill";
onClick = function(view)
cargarArchivosUltimosModificados4()
dialog.dismiss()end
},
{
Button,
text = options[10],
layout_width = "fill";
onClick = function(view)
cargarArchivosUltimosModificados5()
dialog.dismiss()end
},
{
Button,
text = options[11],
layout_width = "fill";
onClick = function(view)
sendFileToFolder(position)
dialog.dismiss()end
}
}
--marcador botones de función
contentView = loadlayout(layout)
dialog.setView(contentView)
dialog.setCancelable(true)
dialog.show()
return true
-- Indicar que se ha manejado el evento
end